package cn.bonoon.kernel.query;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.Query;

import cn.bonoon.kernel.util.StringHelper;

/**
 * <pre>
 * 第三版优化：
 * 
 * </pre>
 * @author jackson
 *
 */
public class QueryLanguageDescriptor {
	
	public final static String XP = "x.";
	private final StringBuilder orderBy;
	private final StringBuilder where;
	private final StringBuilder from;
	private final Map<String, Object> parameters = new HashMap<String, Object>();

	/**
	 * 
	 * @param from
	 * @param where
	 * @param order
	 */
	public QueryLanguageDescriptor(String from, String where, String order){
		this.from = new StringBuilder(from);
		this.where = new StringBuilder(where);
		this.orderBy = new StringBuilder(order);
	}
	
	public void where(String where){
		this.where.append(where);
	}
	
	public void join(String from){
		this.from.append(from);
	}
	
	public void owner(Long id){
		if(null != id && id > 0){
			where.append(" and x.ownerId=").append(id);
		}
	}
	
	public void creater(Long id){
		if(null != id && id > 0){
			where.append(" and x.createrId=").append(id);
		}
	}
	
	public void para(String key, Object val){
		parameters.put(key, val);
	}
	
	public void and(String name, Object val){
		where.append(" and ").append(name);
		if(null != val){
			String pn = name.replace('.', '_');
			where.append(" = :").append(pn);
			parameters.put(pn, val);
		}else{
			where.append(" is null");
		}
	}
	
	public void like(String name, String val){
		String pn = name.replace('.', '_');
		where.append(" and ").append(name);
		if(null != val){
			where.append(" like :").append(pn);
			parameters.put(pn, val);
		}else{
			where.append(" is null");
		}
	}
	
	public void and(String where){
		this.where.append(" and ").append(where);
	}

	public void where(SearchParameter para) {
		if(null != para){
			String n = para.getName();
			String s = para.getSearchName();
			if(StringHelper.isEmpty(s)) s = n;
			if(para.isOr()){
				where.append(" or (");
			}else{
				where.append(" and (");
			}
			where.append(n).append(' ').append(para.getOpt().getOperator()).append(" :").append(s);
			parameters.put(s, para.getValue());
			where(para.getNext());
			where.append(')');
		}
	}

	/**
	 * 如果是可排序的,则第一个排序的方式是按x.ordinal进行排序,后面再追加排序字段,则只能在x.ordinal相同里二次排序
	 * @param sn
	 * @param on
	 */
	public void order(String sn, String on) {
		if (StringHelper.isEmpty(sn)) return;
		if(orderBy.length() > 0) orderBy.append(',');
		orderBy.append(XP).append(sn).append("desc".equalsIgnoreCase(on) ? " desc" : " asc");
	}

	public String toCount() {
		return new StringBuilder("select count(*) ").append(from).append(' ').append(where).toString();
	}
	
	private String _toSelect(StringBuilder select){
		select.append(from).append(' ').append(where);
		if (orderBy.length() > 0) select.append(" order by ").append(orderBy);
		return select.toString();
	}

	public String toSelect() {
		return _toSelect(new StringBuilder("select x "));
	}
	
	public String toSelect(String f) {
		return _toSelect(new StringBuilder("select ").append(f));
	}
	
	private StringBuilder __0(StringBuilder select, String f){
		return select.append(XP).append(f).append(' ');
	}
	
	private StringBuilder __1(StringBuilder select, String f){
		return select.append(',').append(XP).append(f).append(' ');
	}
	
	private StringBuilder __$(){
		return new StringBuilder("select ");
	}
	
	public String toSelect(String f, String f2) {
		return _toSelect(__1(__0(__$(), f), f2));
	}
	
	public String toSelect(String... fs) {
		StringBuilder sb = __0(__$(), fs[0]);
		for (int i = 1; i < fs.length; i++) {
			__1(sb, fs[i]);
		}
		return _toSelect(sb);
	}
	
	public String toSelect(Class<?> clazz, String f){
		StringBuilder sb = __$().append("new ").append(clazz.getName()).append('(');
		__0(sb, f);
		return _toSelect(sb.append(") "));
	}
	
	public String toSelect(Class<?> clazz, String f, String f2){
		StringBuilder sb = __$().append("new ").append(clazz.getName()).append('(');
		__0(sb, f);
		__1(sb, f2);
		return _toSelect(sb.append(") "));
	}
	
	public String toSelect(Class<?> clazz, String f, String f2, String f3){
		StringBuilder sb = __$().append("new ").append(clazz.getName()).append('(');
		__0(sb, f);
		__1(sb, f2);
		__1(sb, f3);
		return _toSelect(sb.append(") "));
	}

	public void parseParameters(Query query) {
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
	}

	public void parseParameters(Query query1, Query query2) {
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query1.setParameter(entry.getKey(), entry.getValue());
			query2.setParameter(entry.getKey(), entry.getValue());
		}
	}
}
